Bun $ Shell
例
code:js
import { $ } from "bun";
await $ls;
gpt-5.icon
1. Bun Shell の正体
Bun が提供する「bash っぽいシェル」を JavaScript/TypeScript から使うための API
import { $ } from "bun"; で使う、テンプレートリテラルタグ ベースのシェル
特徴
クロスプラットフォーム(Windows / macOS / Linux)
ls, rm, cd などは Bun がネイティブ実装 → Node の child_process みたいに外部シェルを叩かない
文字列埋め込みが 自動でエスケープ されるので、コマンドインジェクション対策がされている
Response, Buffer, Bun.file() など JS オブジェクトと stdin/stdout をそのままつなげられる
イメージとしては、Google の zx の Bun 版(かつもう少し言語っぽい) です。
2. 基本の使い方
$ テンプレートでコマンド実行
code:ts
import { $ } from "bun";
await $echo "Hello World!";
デフォルトでは、標準出力にそのまま出る
静かにしたいとき → .quiet()
出力を文字列として取りたい → .text()
code:ts
const text = await $echo "Hello".text(); // "Hello\n"
より低レベルに扱いたいときは、そのまま await すると { stdout, stderr } の Buffer が返る。
code:ts
const { stdout, stderr } = await $echo "Hello".quiet();
3. エラー処理
デフォルト: exit code ≠ 0 なら例外 (ShellError) を投げる
code:ts
try {
const out = await $something-that-may-fail.text();
} catch (err) {
console.log(err.exitCode);
console.log(err.stdout.toString());
console.log(err.stderr.toString());
}
例外を投げてほしくないときは .nothrow() をつける
code:ts
const { exitCode, stdout, stderr } =
await $something-that-may-fail.nothrow().quiet();
if (exitCode !== 0) {
// 自前でエラーハンドリング
}
デフォルト挙動自体も変えられる(グローバル)
code:ts
$.nothrow(); // 以後、全部のコマンドが non-throw
$.throws(true); // 元に戻す
4. リダイレクトとパイプ
Bash と同じ構文をそのまま使える
< : stdin へリダイレクト
> / 1> : stdout をファイルまたは JS オブジェクトへ
2> : stderr
| : パイプ
code:ts
await $echo "Hello" > greeting.txt;
await $cat greeting.txt | wc -c.text();
JS オブジェクトに直接流し込める
code:ts
const buffer = Buffer.alloc(100);
await $echo "Hello" > ${buffer};
console.log(buffer.toString()); // "Hello\n"
code:ts
const response = new Response("hello i am a response body");
const result = await $cat < ${response}.text();
Buffer, ArrayBuffer, TypedArray, Bun.file, Response などに対応。
5. 環境変数とカレントディレクトリ
一時的に env を変える
code:ts
await $echo $FOO.env({ ...process.env, FOO: "bar" });
グローバルデフォルト env を変える
code:ts
$.env({ FOO: "bar" });
await $echo $FOO; // bar
CWD(作業ディレクトリ)
code:ts
await $pwd.cwd("/tmp");
$.cwd("/tmp");
await $pwd; // /tmp
await $pwd.cwd("/") // /
6. 出力の読み取りいろいろ
.text() : 文字列
.json() : JSON パースまでやる
.blob() : Blob
.lines() : for await ... of で 1 行ずつ読む
code:ts
for await (const line of $cat list.txt | grep ${search}.lines()) {
console.log(line);
}
CLI ツールを細かくストリーミング処理したいときに便利。
7. ビルトインコマンド
Bun がネイティブに実装しているコマンド:
cd, ls, rm, echo, pwd, bun, cat, touch, mkdir, which, mv, seq など
→ OS 依存の違いを吸収してくれるので、Windows でも rm や ls が動く、というのがポイントです。
8. ユーティリティ ($.braces, $.escape)
Brace expansion
code:ts
await $.braces(echo {1,2,3});
エスケープロジック
code:ts
$.escape('$(foo) bar "baz"');
// => "\$(foo) \bar\ \"baz\""
逆に「エスケープしたくない」場合は { raw: "..." } を使う。
9. .sh ファイルローダー
.sh 拡張子のスクリプトを Bun Shell で 実行できる
code:sh
# script.sh
echo "Hello World! pwd=$(pwd)"
code:sh
bun ./script.sh # macOS / Linux
bun .\script.sh # Windows
中身は bash 風だが、実行エンジンは Bun Shell なのでクロスプラットフォーム。
10. セキュリティの考え方
Bun Shell は システムの /bin/sh を呼ばない
文字列埋め込み ${...} はすべて 1 個の引数として扱われ、勝手に分割されない
code:ts
const userInput = "my-file.txt; rm -rf /";
// これは安全: "my-file.txt; rm -rf /" という 1 引数になる
await $ls ${userInput};
ただし、こちらのように 自分で新しいシェルを起動した場合は別:
code:ts
await $bash -c "echo ${userInput}";
ここから先は bash -c "..." に丸投げなので、userInput のサニタイズは自分でやる必要がある、という注意点。